/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-11-28
 * Time: 02:17
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;

using tools;

namespace Labb4.Pooman.Misc
{
	/// <summary>
	/// Keeps track of the time, like a sort of global clock
	/// 
	/// Implements the Singleton design pattern (is this nessecary)
	/// </summary>
	public sealed class TimeManager : Manager
	{
		#region members
		
		/// <summary>
		/// The one instance
		/// </summary>
		private static TimeManager		m_Instance = new TimeManager();
		/// <summary>
		/// The real current time
		/// </summary>
		private long					m_CurrentRealTime;
		/// <summary>
		/// The current time of the game (different from real current time if speed != 1.0
		/// </summary>
		private float					m_CurrentGameTime;
		
		/// <summary>
		/// The time passed since the last frame, affected by the speed
		/// </summary>
		private int 					m_GameDeltaTime;
		/// <summary>
		/// The speed of the game time, where 1.0 is normal speed and 0.0 is paused
		/// A negative number has not been tested yet, and may render undefined behaviour
		/// </summary>
		private float					m_Speed;
		
		/// <summary>
		/// Helps calculate the frame rate
		/// </summary>
		private List<int>				m_FrameRateCounter;
		/// <summary>
		/// The current calculated frame rate
		/// </summary>
		private int						m_FrameRate;
		/// <summary>
		/// The number of frames to add to the medium frame rate value
		/// </summary>
		private const int				m_FrameRateMediumValue = 20;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		private TimeManager()
		{
			m_CurrentRealTime = 0;
			m_CurrentGameTime = 0.0f;
			m_GameDeltaTime = 0;
			m_Speed = 1.0f;
			
			m_FrameRateCounter = new List<int>();
			m_FrameRate = 0;
		}
		
		#endregion
		
		#region overrides
		
		/// <summary>
		/// The update routine, updates the current real time, the current game time,
		/// the game delta time, and the frame rate
		/// </summary>
		/// <param name="deltaTime"></param>
		protected override void DoUpdate(ref int deltaTime)
		{
			//update current time
			m_CurrentRealTime += (long)deltaTime;
			
			//update game delta time
			if(m_Speed != 0.0f)
			{
				float delta = (float)deltaTime * m_Speed;
				m_CurrentGameTime += delta;
				m_GameDeltaTime = (int)(delta + 0.5f);
			}
			
			//update framerate
			m_FrameRateCounter.Add(deltaTime);
			
			if(m_FrameRateCounter.Count > m_FrameRateMediumValue)
			{
				int accumulatedFrameTime = 0;
				
				foreach(int it in m_FrameRateCounter)
				{
					accumulatedFrameTime += it;
				}
				
				float avarageFrameTime = (float)accumulatedFrameTime / (float)m_FrameRateMediumValue;
				m_FrameRate = (int)(1000.0f / avarageFrameTime);
				
				m_FrameRateCounter.Clear();
			}
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// The one instance (get)
		/// </summary>
		public static TimeManager Instance
		{
			get
			{
				return m_Instance;
			}
		}
		
		/// <summary>
		/// The current real time (get)
		/// </summary>
		public long CurrentRealTime
		{
			get
			{
				return m_CurrentRealTime;
			}
		}
		
		/// <summary>
		/// The current game time (get)
		/// </summary>
		public float CurrentGameTime
		{
			get
			{
				return m_CurrentGameTime;
			}
		}
		
		/// <summary>
		/// This frame's game delta time (get)
		/// </summary>
		public int GameDeltaTime
		{
			get
			{
				return m_GameDeltaTime;
			}
		}
		
		/// <summary>
		/// The current frame rate (get)
		/// </summary>
		public int FrameRate
		{
			get
			{
				return m_FrameRate;
			}
		}
		
		/// <summary>
		/// The current speed, where 1.0 is normal speed and 0.0 is pause (set/get)
		/// </summary>
		public float Speed
		{
			get
			{
				return m_Speed;
			}
			
			set
			{
				m_Speed = value;
			}
		}
		
		#endregion
	}
}
